package co.yixiang.yshop.module.crm.service.crmcustomer;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.yshop.framework.common.enums.UserTypeEnum;
import co.yixiang.yshop.framework.common.exception.ErrorCode;
import co.yixiang.yshop.framework.common.pojo.PageResult;
import co.yixiang.yshop.framework.common.util.object.BeanUtils;
import co.yixiang.yshop.framework.security.core.util.SecurityFrameworkUtils;
import co.yixiang.yshop.module.crm.controller.admin.basestorage.vo.BaseStoragePageReqVO;
import co.yixiang.yshop.module.crm.controller.admin.crmcustomer.vo.*;
import co.yixiang.yshop.module.crm.dal.dataobject.basestorage.BaseStorageDO;
import co.yixiang.yshop.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import co.yixiang.yshop.module.crm.dal.dataobject.crmcustomercontacts.CrmCustomerContactsDO;
import co.yixiang.yshop.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
import co.yixiang.yshop.module.crm.dal.mysql.crmcustomercontacts.CrmCustomerContactsMapper;
import co.yixiang.yshop.module.crm.enums.CustomerTypesEnum;
import co.yixiang.yshop.module.crm.enums.RelationEnum;
import co.yixiang.yshop.module.crm.service.basestorage.BaseStorageService;
import co.yixiang.yshop.module.crm.service.crmoperatelog.CrmOperatelogService;
import co.yixiang.yshop.module.system.api.dict.DictDataApi;
import co.yixiang.yshop.module.system.api.dict.dto.DictDataRespDTO;
import co.yixiang.yshop.module.system.api.user.AdminUserApi;
import co.yixiang.yshop.module.system.dal.dataobject.user.AdminUserDO;
import co.yixiang.yshop.module.system.service.mail.MailSendService;
import co.yixiang.yshop.module.system.service.sms.SmsSendService;
import co.yixiang.yshop.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil.exception;
import static co.yixiang.yshop.module.crm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS;
import static co.yixiang.yshop.module.crm.enums.ErrorCodeConstants.CUSTOMER_MOBILE_EXISTS;
import static co.yixiang.yshop.module.crm.enums.ErrorCodeConstants.CUSTOMER_WEIXIN_EXISTS;

/**
 * 客户 Service 实现类
 *
 * @author yshop
 */
@Service
@Validated
public class CrmCustomerServiceImpl implements CrmCustomerService {

    @Resource
    private CrmCustomerMapper customerMapper;
    @Resource
    private CrmOperatelogService crmOperatelogService;
    @Resource
    private CrmCustomerContactsMapper customerContactsMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private AdminUserService adminUserService;
    @Resource
    private SmsSendService smsSendService;
    @Resource
    private MailSendService mailSendService;

    @Resource
    private DictDataApi dictDataApi;

    @Resource
    private BaseStorageService baseStorageService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createCustomer(CrmCustomerSaveReqVO createReqVO) {

        // 添加重复性检查
        Map<String, Object> map = validateCustomerDuplicate(createReqVO);

        // 插入
        CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
        customer.setCollectTime(LocalDateTime.now());
        customer.setFollowTime(LocalDateTime.now());
        customer.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
        customer.setMobileRepeat(Convert.toLong(map.get("mobile")));
        customer.setWeixinRepeat(Convert.toLong(map.get("weixin")));
        customerMapper.insert(customer);

        //创建联系人
        CrmCustomerContactsDO crmCustomerContactsDO = CrmCustomerContactsDO.builder()
                .customerId(customer.getId())
                .ownerUserId(SecurityFrameworkUtils.getLoginUserId())
                .name(createReqVO.getName())
                .mobile(createReqVO.getMobile())
                .telephone(createReqVO.getTelephone())
                .remark(createReqVO.getRemark())
                .wechat(createReqVO.getWeixin())
                .build();
        customerContactsMapper.insert(crmCustomerContactsDO);


        //插入日志
        crmOperatelogService.createLog("添加客户", customer.getId(), 0L, 0L);
        // 返回
        return ObjectUtil.isNotEmpty(map.get("msg")) ? Convert.toStr(map.get("msg")) : "添加成功";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String updateCustomer(CrmCustomerSaveReqVO updateReqVO) {
        // 校验存在
        validateCustomerExists(updateReqVO.getId());

        // 添加重复性检查（排除当前客户）
        Map<String, Object> map = validateCustomerDuplicateForUpdate(updateReqVO);

        // 更新
        CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class);
        updateObj.setMobileRepeat(Convert.toLong(map.get("mobile")));
        updateObj.setWeixinRepeat(Convert.toLong(map.get("weixin")));
        customerMapper.updateById(updateObj);

        if (ObjectUtil.isNull(updateReqVO.getNextTime())) {

            LambdaUpdateWrapper<CrmCustomerDO> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(CrmCustomerDO::getNextTime, null)
                    .eq(CrmCustomerDO::getId, updateReqVO.getId());
            customerMapper.update(updateWrapper);
        }
        //插入日志
        crmOperatelogService.createLog("修改客户", updateReqVO.getId(), 0L, 0L);

        return ObjectUtil.isNotEmpty(map.get("msg")) ? Convert.toStr(map.get("msg")) : "修改成功";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCustomer(Long id) {
        // 校验存在
        validateCustomerExists(id);

        // 检查客户表中是否有相同手机号
        CrmCustomerDO existingCustomer = customerMapper.selectOne(
                new LambdaQueryWrapper<CrmCustomerDO>()
                        .eq(CrmCustomerDO::getId, id)
        );


        // 删除
        customerMapper.deleteById(id);

        // 删除之后判断 当前手机号是否还有重复的 如果有重复继续标记 如果没有重复 则不需要再继续标记
        if (ObjectUtil.isNotEmpty(existingCustomer)) {
            // 检查客户表中是否有相同手机号
            List<CrmCustomerDO> list = customerMapper.selectList(
                    new LambdaQueryWrapper<CrmCustomerDO>()
                            .eq(CrmCustomerDO::getMobile, existingCustomer.getMobile())
            );
            if (ObjectUtil.isNotNull(list) && list.size() == 1) {
                LambdaUpdateWrapper<CrmCustomerDO> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(CrmCustomerDO::getMobileRepeat, 0)
                        .eq(CrmCustomerDO::getId, list.get(0).getId());
                customerMapper.update(updateWrapper);
            }
        }
        //插入日志
        crmOperatelogService.createLog("删除客户", id, 0L, 0L);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void openCustomer(Long id) {
        CrmCustomerDO customerDO = customerMapper.selectById(id);
        if (customerDO == null) {
            throw exception(CUSTOMER_NOT_EXISTS);
        }
        //设置拥有0
        customerDO.setOwnerUserId(0L);
        customerMapper.updateById(customerDO);
        //设置联系人的拥有0
        customerContactsMapper.update(CrmCustomerContactsDO.builder().ownerUserId(0L).build(),
                new LambdaQueryWrapper<CrmCustomerContactsDO>().eq(CrmCustomerContactsDO::getCustomerId, id));

        //插入日志
        crmOperatelogService.createLog("放入公海", id, 0L, 0L);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receiveCustomer(Long id) {
        CrmCustomerDO customerDO = customerMapper.selectById(id);
        if (customerDO == null) {
            throw exception(CUSTOMER_NOT_EXISTS);
        }
        customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
        customerDO.setCollectTime(LocalDateTime.now());
        customerDO.setFollowTime(LocalDateTime.now());
        customerMapper.updateById(customerDO);

        //更新联系人
        customerContactsMapper.update(CrmCustomerContactsDO.builder()
                        .ownerUserId(SecurityFrameworkUtils.getLoginUserId()).build(),
                new LambdaQueryWrapper<CrmCustomerContactsDO>().eq(CrmCustomerContactsDO::getCustomerId, id));

        //插入日志
        crmOperatelogService.createLog("公海领取客户", id, 0L, 0L);
    }

    private void validateCustomerExists(Long id) {
        if (customerMapper.selectById(id) == null) {
            throw exception(CUSTOMER_NOT_EXISTS);
        }
    }

    /**
     * 验证客户信息是否重复
     *
     * @param createReqVO 客户创建请求
     */
    private Map<String, Object> validateCustomerDuplicate(CrmCustomerSaveReqVO createReqVO) {
        Map<String, Object> map = new HashMap<>();
        String msg = "";
        int mobile = 0;
        int weixin = 0;

        // 检查手机号是否重复（在客户表和联系人表中）
        if (StrUtil.isNotEmpty(createReqVO.getMobile())) {
            // 检查客户表中是否有相同手机号
            CrmCustomerDO existingCustomer = customerMapper.selectOne(
                    new LambdaQueryWrapper<CrmCustomerDO>()
                            .eq(CrmCustomerDO::getMobile, createReqVO.getMobile())
            );
            if (ObjectUtil.isNotNull(existingCustomer)) {

                AdminUserDO currentUser = new AdminUserDO();
                if (ObjectUtil.isNotNull(existingCustomer.getStalker())) {
                    currentUser = adminUserService.getUser(Convert.toLong(existingCustomer.getStalker()));
                }
                if (existingCustomer != null) {
                    mobile = 1;
                    msg += "跟踪人【" + currentUser.getNickname() + "】已填写该手机号;";
                }
            }

        }

        // 检查微信号是否重复（在客户表和联系人表中）
        if (StrUtil.isNotEmpty(createReqVO.getWeixin())) {
            // 检查客户表中是否有相同微信号
            CrmCustomerDO existingCustomer = customerMapper.selectOne(
                    new LambdaQueryWrapper<CrmCustomerDO>()
                            .eq(CrmCustomerDO::getWeixin, createReqVO.getWeixin())
            );

            if (ObjectUtil.isNotNull(existingCustomer)) {
                AdminUserDO currentUser = new AdminUserDO();
                if (ObjectUtil.isNotNull(existingCustomer.getStalker())) {
                    currentUser = adminUserService.getUser(Convert.toLong(existingCustomer.getStalker()));
                }
                if (existingCustomer != null) {
                    weixin = 1;
                    msg += "跟踪人【" + currentUser.getNickname() + "】已填写该微信号;";
                }
            }

        }
        map.put("msg", msg);
        map.put("weixin", weixin);
        map.put("mobile", mobile);
        return map;
    }

    /**
     * 验证客户信息是否重复（更新时使用，排除当前客户）
     *
     * @param updateReqVO 客户更新请求
     */
    private Map<String, Object> validateCustomerDuplicateForUpdate(CrmCustomerSaveReqVO updateReqVO) {
        Map<String, Object> map = new HashMap<>();
        String msg = "";
        int mobile = 0;
        int weixin = 0;

        // 检查手机号是否重复（在客户表和联系人表中，排除当前客户）
        if (StrUtil.isNotEmpty(updateReqVO.getMobile())) {
            // 检查客户表中是否有相同手机号（排除当前客户）
            var queryWrapper = new LambdaQueryWrapper<CrmCustomerDO>();
            queryWrapper.eq(CrmCustomerDO::getMobile, updateReqVO.getMobile());

            if (ObjectUtil.isNotNull(updateReqVO.getId())) {
                queryWrapper.ne(CrmCustomerDO::getId, updateReqVO.getId());
            }
            CrmCustomerDO existingCustomer = customerMapper.selectOne(queryWrapper);

            if (ObjectUtil.isNotNull(existingCustomer)) {
                AdminUserDO currentUser = new AdminUserDO();
                if (ObjectUtil.isNotNull(existingCustomer.getStalker())) {
                    currentUser = adminUserService.getUser(Convert.toLong(existingCustomer.getStalker()));
                }
                if (existingCustomer != null) {
                    mobile = 1;
                    msg += "跟踪人【" + currentUser.getNickname() + "】已填写该手机号;";
                }
            }
        }

        // 检查微信号是否重复（在客户表和联系人表中，排除当前客户）
        if (StrUtil.isNotEmpty(updateReqVO.getWeixin())) {
            // 检查联系人表中是否有相同微信号;
            var queryWrapper = new LambdaQueryWrapper<CrmCustomerDO>()
                    .eq(CrmCustomerDO::getWeixin, updateReqVO.getWeixin());
            if (ObjectUtil.isNotNull(updateReqVO.getId())) {
                queryWrapper.ne(CrmCustomerDO::getId, updateReqVO.getId());
            }
            CrmCustomerDO existingContact = customerMapper.selectOne(queryWrapper);
            if (ObjectUtil.isNotNull(existingContact)) {
                AdminUserDO currentUser = new AdminUserDO();
                if (ObjectUtil.isNotNull(existingContact.getStalker())) {
                    currentUser = adminUserService.getUser(Convert.toLong(existingContact.getStalker()));
                }
                if (existingContact != null) {
                    weixin = 1;
                    msg += "跟踪人【" + currentUser.getNickname() + "】已填写该微信号;";
                }
            }

        }

        map.put("msg", msg);
        map.put("weixin", weixin);
        map.put("mobile", mobile);
        return map;
    }

    @Override
    public CrmCustomerDO getCustomer(Long id) {
        return customerMapper.selectById(id);
    }

    @Override
    public PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO) {

        Long adminId = SecurityFrameworkUtils.getLoginUserId();

        // 获取当前用户信息，判断是否为管理员
        AdminUserDO currentUser = adminUserService.getUser(adminId);
        boolean isAdministrator = currentUser != null && currentUser.getIsAdministrator() != null && currentUser.getIsAdministrator() == 1L;

        // 使用带权限验证的查询方法
        // 通过sys_role_auth_data表验证当前用户对客户storageId的权限
        // 只有当前用户在sys_role_auth_data表中有对应storageId权限的客户才会被查询出来
        return customerMapper.selectPageWithAuth(pageReqVO, adminId, isAdministrator);
    }

    @Override
    public PageResult<Map<String, Object>> getCustomerStatistics(CrmCustomerPageReqVO pageReqVO) {
        Long adminId = SecurityFrameworkUtils.getLoginUserId();
        // 获取当前用户信息，判断是否为管理员
        AdminUserDO currentUser = adminUserService.getUser(adminId);
        boolean isAdministrator = currentUser != null && currentUser.getIsAdministrator() != null && currentUser.getIsAdministrator() == 1L;

        List<CrmCustomerDO> customerStatistics = customerMapper.getCustomerStatistics(pageReqVO, adminId, isAdministrator);

        // 查询客户来源字典数据
        List<DictDataRespDTO> customerSourceDictList = dictDataApi.getDictDataList("customer_source");
        // 查询仓库信息
        BaseStoragePageReqVO vo = new BaseStoragePageReqVO();
        vo.setPageSize(pageReqVO.getPageSize());
        vo.setPageNo(pageReqVO.getPageNo());

        PageResult<BaseStorageDO> storagePage = baseStorageService.getStoragePage(vo);

        // 处理客户统计数据，按来源分组统计
        List<Map<String, Object>> data = new ArrayList<>();
        for (var storage : storagePage.getList()) {
            Map<String, Object> statItem = new HashMap<>();
            statItem.put("storageName", storage.getStorageName());
            int total = 0;
            for (var item : customerSourceDictList) {
                int size = customerStatistics.stream().filter(customer -> StrUtil.equals("" + customer.getStorageName(), storage.getStorageName()) && StrUtil.equals("" + customer.getSource(), item.getValue())).toList().size();
                statItem.put(item.getLabel(), size);
                total += size;
            }
            statItem.put("total", total);
            data.add(statItem);
        }

        PageResult<Map<String, Object>> result = new PageResult<>();
        result.setList(data);
        result.setTotal(storagePage.getTotal());
        List<String> sumList = new ArrayList<>();
        for (var item : customerStatistics) {
            DictDataRespDTO dictDataRespDTO = customerSourceDictList.stream().filter(i -> StrUtil.equals("" + item.getSource(), i.getValue())).toList().get(0);
            sumList.add(dictDataRespDTO.getLabel());
        }
        result.setSumList(sumList);

        return result;
    }


    @Override
    public void sendSms(SmsTemplateSendVO sendVO) {
        List<CrmCustomerContactsDO> crmCustomerDOS = null;
        if (sendVO.getIsCustomer()) {
            crmCustomerDOS = customerContactsMapper.selectList(new LambdaQueryWrapper<CrmCustomerContactsDO>().
                    in(CrmCustomerContactsDO::getCustomerId, sendVO.getCustomerIds()));
        } else {
            crmCustomerDOS = customerContactsMapper.selectList(new LambdaQueryWrapper<CrmCustomerContactsDO>().
                    in(CrmCustomerContactsDO::getId, sendVO.getCustomerIds()));
        }

        if (crmCustomerDOS == null || crmCustomerDOS.isEmpty()) {
            throw exception(new ErrorCode(202409100, "客户信息不存在"));
        }
        crmCustomerDOS.forEach(customer -> {
            //发送短信
            if (StrUtil.isNotEmpty(customer.getMobile())) {
                smsSendService.sendSingleSms(customer.getMobile(), customer.getId(), UserTypeEnum.CUSTOMER.getValue(),
                        sendVO.getTemplateCode(), sendVO.getTemplateParams());
            }
        });

    }

    @Override
    public void sendMail(MailTemplateSendVO sendVO) {
        List<CrmCustomerContactsDO> crmCustomerDOS = null;
        if (sendVO.getIsCustomer()) {
            crmCustomerDOS = customerContactsMapper.selectList(new LambdaQueryWrapper<CrmCustomerContactsDO>().
                    in(CrmCustomerContactsDO::getCustomerId, sendVO.getCustomerIds()));
        } else {
            crmCustomerDOS = customerContactsMapper.selectList(new LambdaQueryWrapper<CrmCustomerContactsDO>().
                    in(CrmCustomerContactsDO::getId, sendVO.getCustomerIds()));
        }
        if (crmCustomerDOS == null || crmCustomerDOS.isEmpty()) {
            throw exception(new ErrorCode(202409101, "客户信息不存在"));
        }
        crmCustomerDOS.forEach(customer -> {
            //发送邮件
            if (StrUtil.isNotEmpty(customer.getEmail())) {
                mailSendService.sendSingleMail(customer.getEmail(), customer.getId(), UserTypeEnum.CUSTOMER.getValue(),
                        sendVO.getTemplateCode(), sendVO.getTemplateParams());
            }
        });
    }

}